package gen.tools.withdraw;

import gen.tools.CommitMediator;
import gen.tools.Widgets;
import gen.tools.deployByDelivery.FileStr;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.tmatesoft.svn.core.SVNCommitInfo;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.io.ISVNEditor;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.io.diff.SVNDeltaGenerator;
import org.tmatesoft.svn.core.wc.SVNWCUtil;

import com.google.gson.Gson;

public class Withdraw4SDEL extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    public Withdraw4SDEL() {
        super();
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request,response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		final Widgets wid = new Widgets();
		request.setCharacterEncoding( wid.UIcodeSet );
		response.setCharacterEncoding( wid.UIcodeSet );
		response.setContentType("application/json");
		
		/*
		 * 1. 寫入需求
		 * 2. 記錄F部署
		 * 3. 記錄部署計劃
		 * 3. 將檔案寫入SVN CM OL 封裝檔 
		 * 4. 記錄交付事件
		 * 5. 簽入分公司的SVN Repo
		 * 6. 記錄"SVN交付記錄"
		 * 
		 **/
		
		final String empId = request.getParameter("empId");
		final String subsysId = request.getParameter("subsysId");
		final int tarDeplMainSN = Integer.parseInt( request.getParameter("tarDeplMainSN") );	//交付方的部署計畫代號
		final int tarDeliverySN = Integer.parseInt( request.getParameter("tarDeliverySN") );	//交付方的交付事件流水號
		
		String sql = "";
		final StrucW4SDEL sw = new StrucW4SDEL();
		Connection conn = null;
		Connection tarConn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		ResultSet rs2 = null;
		
		SVNRepository souRepo = null;
		SVNRepository tarRepo = null;
		ISVNEditor editor = null;
		InputStream ins = null;
		FileOutputStream fos = null;
		File df = null;
		File dd = null;
		
		SVNProperties fileProperties = new SVNProperties();
		final ArrayList<FileStr> fses = new ArrayList<FileStr>();
		SVNCommitInfo info = null;
		final SVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator();
		final int targetSystemId = 7;
		int localSystemId = Integer.parseInt( request.getParameter("localSystemId") );	//本機系統的系統ID
		try {
			conn = wid.getConn();
			//建立<交付方>資料庫連線
			tarConn = wid.getTarConnection(targetSystemId );
			
			final int localDeplMainSN = wid.getCurrentSN("deplmain"); 			//目前部署計劃的流水號
			sw.setDeplMainSN(localDeplMainSN);
			
			//新增部署計劃<接收方>
			sql = "INSERT INTO deplmain (deplmainSN,sysSN,creator,createdDateTime,subsysid,tarDeplmainSN) VALUES (?,?,?,?,?,?)";
			ps = conn.prepareStatement( sql );
			ps.setInt(1, localDeplMainSN);
			ps.setInt(2, localSystemId);
			ps.setString(3, empId);
			ps.setTimestamp(4, wid.cDT() );
			ps.setString(5, subsysId );
			ps.setInt(6,tarDeplMainSN);
			ps.execute();
			
			//更新部署計劃 回 交付方  (回寫部署計畫代碼)
			sql = "UPDATE deplmain SET tarDeplmainSN=? WHERE deplmainSN=?";
			ps = tarConn.prepareStatement( sql );
			ps.setInt(1, localDeplMainSN);
			ps.setInt(2, tarDeplMainSN);
			ps.execute();
			
			final int deliverySN = wid.getCurrentSN("deltask");	//取得交付事件的流水號
			sw.setDeliverySN(deliverySN);
			
			sql = "SELECT deliveryComment FROM deltask WHERE deliverySN=?";
			ps = tarConn.prepareStatement( sql );
			ps.setInt(1, tarDeliverySN);
			rs = ps.executeQuery();
			
			String comment = "";
			
			if ( rs.next() ) {
				comment = rs.getString("deliveryComment");
			}
			
			//產生交付事件<接收方>
			sql = "INSERT INTO deltask (deliverySN,isDeliver,deliveryComment,deliveryTarSN,deplmainSN,souSysSN,tarSysSN,statusSN) VALUES ("+deliverySN+",?,?,?,?,?,?,?)";
			ps = conn.prepareStatement( sql );
			ps.setString(1,"f");
			ps.setString(2, comment );
			ps.setInt(3, tarDeliverySN);
			ps.setInt(4, localDeplMainSN);
			ps.setInt(5, localSystemId);
			ps.setInt(6, targetSystemId);
			ps.setInt(7, 5);	//提領失敗(先預設提領失敗，成功後再改)
			ps.execute();
			
			//變更交付方的狀態	5 提領失敗
			wid.updateDeltaskStatus(tarDeliverySN, 5, wid.getTarConnection(targetSystemId) );
			
			
			//更新交付事件<交付方>  將接收方的交付序號同步至交付方
			sql = "UPDATE deltask SET deliveryTarSN=? WHERE deliverySN=?";
			ps = tarConn.prepareStatement( sql );
			ps.setInt(1, deliverySN );
			ps.setInt(2, tarDeliverySN );
			ps.execute();
			
			//SVM連線建立 
			final ArrayList<String> souConnInfo = wid.getSVNConn4Delivery(localSystemId, targetSystemId);	//連往交付方的SVN連線資訊
			final ArrayList<String> tarConnInfo = wid.getSVN4SubsysConnInfo(subsysId, 7);			//連往接收方的SVN連線資訊(也就是本地)
			
			ISVNAuthenticationManager authManager = SVNWCUtil.createDefaultAuthenticationManager(tarConnInfo.get(1), tarConnInfo.get(2));
			tarRepo = SVNRepositoryFactory.create( SVNURL.parseURIEncoded( tarConnInfo.get(0) ) );
		    tarRepo.setAuthenticationManager(authManager);
		    
			editor = tarRepo.getCommitEditor(null,new CommitMediator() );
			
			sql = "SELECT depldetailid,localPath,localFile,localVer,depPath,comReqsNum,isnonweb,fileSizeInByte FROM depldetail WHERE deplmainSN=? ORDER BY localFile DESC";
			ps = tarConn.prepareStatement(sql);
			ps.setInt(1, tarDeplMainSN);
			rs = ps.executeQuery();
			editor.openRoot(-1);
			while ( rs.next() ) {
				
				final String fn = rs.getString("localFile");	//部署檔名
				
				final String extension = fn.substring(fn.lastIndexOf("."), fn.length() ); 	//副檔名  ex: ".ear" ".war" (含一個點)
				final String tmpFileName = System.currentTimeMillis()+extension;			//為節省記憶體，先寫入磁碟，複制完再刪除
				
				System.out.println("The temporary file for "+fn+" is "+ tmpFileName);
				dd = new File(tmpFileName);
				final String depFile = fn;
				final int detailId = rs.getInt("depldetailid");
				final int tarVer = rs.getInt("localVer");
				
				
				final FileStr fs = new FileStr();
				fs.setFileName(fn);
				fs.setTargetVer(tarVer);
				fses.add(fs);
				
				souRepo = SVNRepositoryFactory.create( SVNURL.parseURIEncoded( souConnInfo.get(0) ) );
				authManager = SVNWCUtil.createDefaultAuthenticationManager(souConnInfo.get(1), souConnInfo.get(2) );
				souRepo.setAuthenticationManager(authManager);
				fos = new FileOutputStream (dd);
				
				souRepo.getFile( depFile,tarVer, fileProperties, fos);
				df = new File( tmpFileName );
			    ins = new FileInputStream( tmpFileName );
		        
		        try {
		        	editor.openFile( depFile, -1);	/** -1 或 正確的版本都可以 **/
		        } catch(SVNException e) {
		        	editor.addFile( depFile, null /** 從另一個"路逕" 複製過來 **/, -1 /** 另一個路逕上的那個版本 **/);
		        }
		        
	    		editor.applyTextDelta( depFile, null); 
	    		final String baseChecksum = deltaGenerator.sendDelta( depFile, ins, editor, true);
	    	    editor.textDeltaEnd( depFile );
	    	    editor.closeFile( depFile, baseChecksum );
	    	    
	    	    
				//	寫入部署細項<接收方>
				sql = "INSERT INTO depldetail (deplmainSN,depldetailid,localFile,isnonweb,localPath,depPath,localVer,depOrder,comReqsNum,creator,createdDateTime,fileSizeInByte) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)";
				ps = conn.prepareStatement(sql);
				ps.setInt(1, localDeplMainSN);  //deplmainSN
				ps.setInt(2, detailId);			//depldetailid
				ps.setString(3, fn);			//localFile
				ps.setString(4, rs.getString("isnonweb") );			//isnonweb
				ps.setString(5, rs.getString("localPath") );			//localPath
				ps.setString(6, rs.getString("depPath") );			//depPath
				ps.setLong(7, 0);				//版次
				ps.setInt(8, 0);								//depOrder
				ps.setInt(9, rs.getInt("comReqsNum"));				//comReqsNum
				ps.setString(10, empId);
				ps.setTimestamp(11, wid.cDT() );
				ps.setInt(12, rs.getInt("fileSizeInByte") );
				ps.execute();
				
				//記錄SVN CM OL 與 分公司SVN的對應關係<接收方>
				final int svnMappingSN = wid.getCurrentSN("delsvn");
				sql = "INSERT INTO delsvn (svnMappingSN,deliverySN,fromPath,fromFile,fromVer,toPath,toFile,toVer,sysSN,fromSVNhost,toSVNhost) VALUES ("+svnMappingSN+",?,?,?,?,?,?,?,?,?,?)";
				ps = conn.prepareStatement(sql);
	    	    ps.setInt(1, deliverySN);														/*	交付方 交付代碼		*/											
	    	    ps.setString(2, "" );						/*	交付方	SVN相對路徑		*/
	    	    ps.setString(3, fn );							/*	交付方 檔案名稱		*/
	    	    ps.setInt(4, tarVer );								/*	交付方	版次		*/
	    	    ps.setString(5, "" );						/*	接收方 SVN相對路徑		*/
	    	    ps.setString(6, depFile );							/*	接收方 檔案名稱		*/
	    	    ps.setLong(7, 0);															/*	接收方	版次		*/
	    	    ps.setInt(8, localSystemId);															/*	交付端給了誰 (他給了誰)		*/
	    	    ps.setString(9, souConnInfo.get(0) );				/*	交付方 主機		*/
	    	    ps.setString(10, tarConnInfo.get(0) );			/*	接收方 主機		*/
	    	    ps.execute();
	    	    
	    	    fos.close();
	    	    System.out.println("Is file "+tmpFileName+" deleted? "+df.getAbsoluteFile().delete());
	    	    
			}
			//開始處理檔案
			info = editor.closeEdit();			//本次提交結束
			final long localVer = info.getNewRevision();
			//將版次資訊更新<接收方>
			sql = "UPDATE depldetail SET localVer=? WHERE deplmainSN=?";
			ps = conn.prepareStatement(sql);
			ps.setLong(1, localVer );
			ps.setInt(2, localDeplMainSN);
			ps.execute();
			
			//版次對應資訊更新<接收方>
			sql = "UPDATE delsvn SET toVer=? WHERE deliverySN=?";
			ps = conn.prepareStatement(sql);
			ps.setLong(1, localVer );
			ps.setInt(2, deliverySN);
			ps.execute();
			//版次對應資訊更新<交付方>
			ps = tarConn.prepareStatement(sql);
			ps.setLong(1, localVer );
			ps.setInt(2, tarDeliverySN);
			ps.execute();
			
			
			for(int i=0; i<fses.size();i++) {
				fses.get(i).setLocalVer((int)localVer);
			}
			//變更接收方的狀態	6 已提領待送審
			wid.updateDeltaskStatus(deliverySN, 6, wid.getConn());
			//變更交付方的狀態	6 已提領待送審
			wid.updateDeltaskStatus(tarDeliverySN, 6, wid.getTarConnection(targetSystemId) );
			
			// 寫入需求
			System.out.println("查詢交付方，部署計畫"+tarDeplMainSN+"相關的需求");
			sql = "SELECT t1.depldetailid,t2.reqSID,t2.reqDESC FROM mpreqfiles t1,reqs t2 WHERE t1.deplmainSN=? AND t1.reqSN=t2.reqId";
			ps = tarConn.prepareStatement(sql);
			ps.setInt(1, tarDeplMainSN);
			rs = ps.executeQuery();
			
			while ( rs.next() ) {
				System.out.println("進來了");
				final String reqSID = rs.getString("reqSID");
				System.out.println("reqId:"+reqSID);
				final String reqDesc = rs.getString("reqDESC");
				System.out.println("reqDesc:"+reqDesc);
				final int reqStatus = wid.isReqExisted(reqSID, reqDesc);
				System.out.println("reqStatus:"+reqStatus);
				final int detailId = rs.getInt("depldetailid");
				System.out.println("detailId:"+detailId);
				
				if( reqStatus == 3 ) {	//3 是不存在，所以要新增入需求的記錄中
					// 記錄需求<接收方>
					sql = "INSERT INTO reqs (reqDesc,reqSID,subsysId,creatorId,cDT,sysSN) VALUES (?,?,?,?,?,?)";
					ps = conn.prepareStatement(sql);
					ps.setString(1, reqDesc );
					ps.setString(2, reqSID );
					ps.setString(3, subsysId );
					ps.setString(4, empId );
					ps.setTimestamp(5, wid.cDT() );
					ps.setInt(6, targetSystemId );	//因為是從別人那裡取來的，所以這裡要寫目標的ID
					ps.execute();
				}
				sql = "SELECT reqId FROM reqs WHERE reqSID=?";
				ps = conn.prepareStatement(sql);
				ps.setString(1, reqSID );
				rs2 = ps.executeQuery();
				rs2.next();
				final int reqId = rs2.getInt("reqId");
				
				sql = "INSERT INTO mpreqfiles (deplmainSN,depldetailid,reqSN,creator,createdDateTime) VALUES (?,?,?,?,?)";
				ps = conn.prepareStatement(sql);
				ps.setInt(1, localDeplMainSN );
				ps.setInt(2, detailId);
				ps.setInt(3, reqId);
				ps.setString(4, empId);
				ps.setTimestamp(5, wid.cDT() );
				ps.execute();
			}
			
			sql = "SELECT depldetailid,bssid,subsysid,squadid FROM mpdeplunitsqu WHERE deplmainSN=?";
			ps = tarConn.prepareStatement(sql);
			ps.setInt(1, tarDeplMainSN);
			rs = ps.executeQuery();
			while ( rs.next() ) {
				sql = "INSERT INTO mpdeplunitsqu (deplmainSN,depldetailid,bssid,subsysId,squadId,creator,createdDateTime) VALUES(?,?,?,?,?,?,?)";
				ps = conn.prepareStatement(sql);
				ps.setInt(1, localDeplMainSN );
				ps.setInt(2, rs.getInt("depldetailid"));
				ps.setString(3, rs.getString("bssid"));
				ps.setString(4, rs.getString("subsysid"));
				ps.setString(5, rs.getString("squadId"));		//第一個squadId
				ps.setString(6, empId);
				ps.setTimestamp(7, wid.cDT() );
				ps.execute();
			}
			
			sw.setRes("OK");
		} catch(Exception e) {
			wid.errLog(e);
			sw.setRes( e.toString() );
		} finally {
			try {
				if ( df !=null ) {df.delete(); }
				if ( dd !=null ) {dd.delete(); }
				if ( ins !=null ) {ins.close();}
				if ( fos !=null ) {fos.close();}
				if ( rs !=null ) {rs.close();}
				if ( rs2 !=null ) {rs2.close();}
				if ( ps !=null ) {ps.close();}
				if ( conn !=null ) {conn.close();}
				if ( tarConn !=null ) {tarConn.close();}
				if ( souRepo!= null ) { souRepo.closeSession(); }
				if ( tarRepo!= null ) { tarRepo.closeSession(); }
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		sw.setFses(fses);
		
		response.getWriter().write( new Gson().toJson(sw) );
	}

}
